package http

import (
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
	"webProxy/pkg/data"
)

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		// if origin != "" {
		// 可将将* 替换为指定的域名
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
		c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")
		// }

		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}

		c.Next()
	}
}

func StartHttp(add string) {
	r := gin.Default()
	r.Use(gin.Recovery())
	r.Use(Cors()) // 跨域中间件
	initRouter(r)

	go func() {
		if err := r.Run(add); err != nil {
			log.Printf("gin run fail, err:%s\n", err.Error())
			os.Exit(-1)
		}
	}()
}

func initRouter(r *gin.Engine) {
	r.GET("/proxy/fetch", proxyFetch)
	r.GET("/proxy/v2/fetch", proxyFetchV2)
}

// type proxyFetchReqeust struct {
// 	Url         string `json:"url"`
// 	Millisecond int64  `json:"millisecond"` // 毫秒时间戳
// }

//
// type proxyFetchResponseItem struct {
// 	Path   string `json:"path"`
// 	Method string `json:"method"`
// 	Status int64  `json:"status"`
// }

type proxyFetchResponse struct {
	ErrCode int64       `json:"errCode"`
	Desc    string      `json:"desc"`
	Data    interface{} `json:"data"`
}

func proxyFetch(ctx *gin.Context) {
	startTime := time.Now()
	recvFlag := 0 // 0: timeout, 1: recv data
	var recvTime time.Time
	defer func() {
		if recvFlag == 0 {
			log.Printf("proxyFetch elepsed, timeout:%s", time.Since(startTime))
		} else {
			log.Printf("proxyFetch elepsed, recv data, wait:%s, recvTime:%s", time.Since(startTime), time.Since(recvTime))
		}
	}()

	msgSub, err := generateMsgHandler(ctx.Request.RemoteAddr, []string{})
	if err != nil {
		ctx.JSON(http.StatusOK, &proxyFetchResponse{
			ErrCode: -1,
			Desc:    err.Error(),
		})
		return
	}

	data.AddSubscriber(msgSub)
	defer data.RemSubscriber(msgSub.UUId)

	select {
	case msg := <-msgSub.MsgChan:
		recvTime = msg.RecvTime
		recvFlag = 1
		ctx.JSON(http.StatusOK, &proxyFetchResponse{
			ErrCode: http.StatusOK,
			Desc:    "success",
			Data:    msg,
		})
		return
	case <-time.NewTimer(time.Duration(10) * time.Second).C:
		ctx.JSON(http.StatusNotModified, &proxyFetchResponse{
			ErrCode: http.StatusOK,
			Desc:    "empty",
			Data:    nil,
		})
		return
	}
}

type proxyFetchV2Request struct {
	Port       int64  `json:"port" form:"port"`             // 监听的proxy端口
	PathFilter string `json:"pathFilter" form:"pathFilter"` // 监听的端口路径, 逗号分割
}

func proxyFetchV2(ctx *gin.Context) {
	startTime := time.Now()
	recvFlag := 0 // 0: timeout, 1: recv data
	var recvTime time.Time
	defer func() {
		if recvFlag == 0 {
			log.Printf("proxyFetchV2 elepsed, timeout:%s", time.Since(startTime))
		} else {
			log.Printf("proxyFetchV2 elepsed, recv data, wait:%s, recvTime:%s", time.Since(startTime), time.Since(recvTime))
		}
	}()

	req := &proxyFetchV2Request{}
	if err := ctx.ShouldBindQuery(req); err != nil {
		ctx.JSON(http.StatusOK, &proxyFetchResponse{
			ErrCode: -1,
			Desc:    err.Error(),
		})
		return
	}

	pathFilter := make([]string, 0)
	if len(req.PathFilter) > 0 {
		pathFilter = strings.Split(req.PathFilter, ",")
	}

	msgSub, err := generateMsgHandler(ctx.Request.RemoteAddr, pathFilter)
	if err != nil {
		ctx.JSON(http.StatusOK, &proxyFetchResponse{
			ErrCode: -1,
			Desc:    err.Error(),
		})
		return
	}

	data.AddSubscriberV2(msgSub, req.Port)
	defer data.RemSubscriberV2(msgSub.UUId, req.Port)

	select {
	case msg := <-msgSub.MsgChan:
		recvTime = msg.RecvTime
		recvFlag = 1
		ctx.JSON(http.StatusOK, &proxyFetchResponse{
			ErrCode: http.StatusOK,
			Desc:    "success",
			Data:    msg,
		})
		return
	case <-time.NewTimer(time.Duration(10) * time.Second).C:
		ctx.JSON(http.StatusNotModified, &proxyFetchResponse{
			ErrCode: http.StatusOK,
			Desc:    "empty",
			Data:    nil,
		})
		return
	}
}

// pathFilter 路径筛选, 空表示不进行筛选
func generateMsgHandler(remoteAddr string, pathFilter []string) (*data.SubscriberHandler, error) {
	bUUId, err := uuid.NewUUID()
	if err != nil {
		return nil, err
	}
	msgSub := &data.SubscriberHandler{
		RemoteAddr: remoteAddr,
		UUId:       bUUId.String(),
		MsgChan:    make(chan *data.MsgInfo, 1),
		PathFilter: pathFilter,
	}
	return msgSub, nil
}
